import asyncio
import logging
import time

from collections.abc import Awaitable

logging.basicConfig(level=logging.DEBUG,format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s')
logger = logging

async def get_html(url):
    logger.info(f"get_html {url} begin")
    #注意 这里await 后面不能用 time.sleep    await + Awaitable对象
    await asyncio.sleep(2)
    #time.sleep(2)    #这样无法起到协程的作用
    logger.info(f"get_html {url} end")
    return "html ok"

def notice(future):
    logger.info("收到 网页已下载成功 的消息")
    logger.info(future.result())

def send_email(future,email):
    logger.info(f"send to {email} {future.result()}")

def test_loop():
    started = time.time()
    looper = asyncio.get_event_loop()
    looper.run_until_complete(get_html("https://www.baidu.com"))
    logger.info(time.time()-started)

def test_loop_future():
    started = time.time()
    looper = asyncio.get_event_loop()
    # 类似 thread  的 future 可以获取协程执行返回的结果
    future = asyncio.ensure_future(get_html("https://www.a.com"))    # ensure_future 内部其实也是调用了 loope.create_task
    #协程执行完毕时执行一个回调函数,此函数需要接收一个future参数
    future.add_done_callback(notice)
    looper.run_until_complete(future)
    print(future.result())

    # task 和 future
    # task = looper.create_task(get_html("http://www.b.com"))
    # looper.run_until_complete(task)
    # logger.info(time.time()-started)
    #print(task.result())

def test_loop_future_callback():
    looper = asyncio.get_event_loop()
    future = asyncio.ensure_future(get_html("https://www.a.com"))
    #回调,回调函数默认只能接收future一个参数，如果需要接收额外参数怎么办？ 偏函数需要介入
    from functools import partial
    future.add_done_callback(partial(send_email,email="caoyx@163.com"))
    looper.run_until_complete(future)


def test_loop_multi_task():
    started = time.time()
    looper = asyncio.get_event_loop()
    tasks = [get_html(f"http://www.a.com/{i}.html") for i in range(10)]
    #looper.run_until_complete(asyncio.wait(tasks))
    looper.run_until_complete(asyncio.gather(*tasks))
    logger.info(time.time()-started)

def test_loop_gather():
    started = time.time()
    looper = asyncio.get_event_loop()
    group1 = [get_html(f"http://www.a.com/{i}.html") for i in range(2)]
    group2 = [get_html(f"http://www.b.com/{i}.html") for i in range(4)]
    #looper.run_until_complete(asyncio.gather(*group1,*group2))
    group1 = asyncio.gather(*group1)
    group2 = asyncio.gather(*group2)
    group2.cancel()
    looper.run_until_complete(asyncio.gather(group1,group2))

    logger.info(time.time()-started)

if __name__ == '__main__':
    test_loop_gather()